﻿namespace OpenComposite.UserAccess
{
	using System;
	using System.ComponentModel;
	using System.Data;
	using System.Data.SqlClient;
	using System.Diagnostics;
	using System.IO;
	using System.Windows.Forms;

	using Microsoft.Win32;

	using OpenComposite.Base;

	partial class FormLogon : Form
	{
		#region Initialization

		/// <summary>
		/// Create the logon dialog.
		/// </summary>
		internal FormLogon(Guid applicationId)
		{
			this.ApplicationId = applicationId;
			this.ShowCreateNewOrganizationForm = null;

			InitializeComponent();

			string exe = Application.ExecutablePath;
			string full = Path.GetDirectoryName(exe);
			string pathconfig = Path.Combine(Application.UserAppDataPath/*full*/, Environment.UserName + ".icfg");

			lblSQLServer.Visible = true;
			txtSqlServer.Visible = true;

			m_settings = new UserSettings(pathconfig);

			restoreSettings();
		}

		#endregion Initialization

		#region Public Members

		#region Events

		public event EventHandler<NewOrgEventArgs> ShowCreateNewOrganizationForm;

		#endregion

		#region Properties

		/// <summary>
		/// Gets the application id.
		/// </summary>
		/// <value>The application id.</value>
		public Guid ApplicationId
		{
			get;
			private set;
		}

		/// <summary>
		/// Gets or sets the sub title.
		/// </summary>
		/// <value>The sub title.</value>
		public string SubTitle
		{
			get { return lblSubTitle.Text; }
			set { lblSubTitle.Text = value; }
		}

		/// <summary>
		/// Gets or sets the title.
		/// </summary>
		/// <value>The title.</value>
		public string Title
		{
			get { return lblTitle.Text; }
			set { lblTitle.Text = value; }
		}

		/// <summary>
		/// Gets or sets the user access.
		/// </summary>
		/// <value>The user access.</value>
		public UserAccessController UserAccess
		{
			get { return _userAccess; }
			set { _userAccess = value; }
		}

		/// <summary>
		/// Gets or sets the version.
		/// </summary>
		/// <value>The version.</value>
		public string Version
		{
			get { return lblVersion.Text; }
			set { lblVersion.Text = value; }
		}

		#endregion Properties

		#endregion Public Members

		#region Private Members

		#region Fields

		private bool _expanded = false;
		ToolTip _tooltip = new ToolTip();
		private UserAccessController _userAccess;
		private UserSettings m_settings;

		#endregion Fields

		#region Event Handlers

		private void FormLogon_Load(object sender, EventArgs e)
		{
			//fillCredentials();
			this.Focus();

			if ( txtSqlServer.TextLength == 0 || txtDatabase.TextLength == 0 ||
				( ( txtDbUser.TextLength == 0 || txtDbPassword.TextLength == 0 ) &&
					!checkWinAuthentication.Checked ) ) {
				_expanded = true;
				loadSettingsFromRegistry();
			} else {
				_expanded = false;
			}
			setExpandedView(_expanded);
		}

		private void FormLogon_Shown(object sender, EventArgs e)
		{
			this.TopMost = false;
			this.BringToFront();
			if ( txtOrg.TextLength == 0 )
				txtOrg.Focus();
			else if ( txtUser.TextLength == 0 )
				txtUser.Focus();
			else if ( txtPassword.TextLength == 0 )
				txtPassword.Focus();
		}

		/// <summary>
		/// Button Cancel.
		/// </summary>
		private void btnCancel_Click(object sender, System.EventArgs e)
		{
			this.DialogResult = DialogResult.Cancel;
			this.Close();
		}

		/// <summary>
		/// btnDetails clicked event.
		/// </summary>
		private void btnDetails_Click(object sender, EventArgs e)
		{
			_expanded = !_expanded;
			setExpandedView(_expanded);
		}

		/// <summary>
		/// OK Button.
		/// </summary>
		private void btnOk_Click(object sender, System.EventArgs e)
		{
			doLogin();
		}

		private void checkWinAuthentication_CheckedChanged(object sender, EventArgs e)
		{
			CheckBox cb = sender as CheckBox;
			if ( cb == null )
				return;

			txtDbUser.Enabled = !cb.Checked;
			txtDbPassword.Enabled = !cb.Checked;
		}

		private void linkTestConn_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			testDBConn(true);
		}

		private void txt_Enter(object sender, EventArgs e)
		{
			TextBox txt = sender as TextBox;
			if ( txt != null )
				txt.SelectAll();
		}

		private void btnCreateNewOrg_Click(object sender, EventArgs e)
		{
			doCreateNewOrg();
		}

		#endregion Event Handlers

		#region Methods

		private string createConnectionString()
		{
			SqlConnectionStringBuilder connBuilder = new SqlConnectionStringBuilder();
			connBuilder.ConnectTimeout = (int)numTimeOut.Value;
			connBuilder.DataSource = txtSqlServer.Text;
			connBuilder.InitialCatalog = txtDatabase.Text;
			connBuilder.PacketSize = 4096;
			connBuilder.IntegratedSecurity = checkWinAuthentication.Checked;
			if ( !checkWinAuthentication.Checked ) {
				connBuilder.PersistSecurityInfo = true;
				connBuilder.UserID = txtDbUser.Text;
				connBuilder.Password = txtDbPassword.Text;
			}
			return connBuilder.ConnectionString;
		}

		private void doLogin()
		{
			try {
				string nam = txtUser.Text.Trim();
				string pwd = txtPassword.Text.Trim();
				string org = txtOrg.Text.Trim();
				if ( nam == "" || org == "" ) {
					Helper.ShowInfo("Username and Organization can't be empty.");
					return;
				}

				string svr = txtSqlServer.Text.Trim();
				string dat = txtDatabase.Text.Trim();
				string dbu = txtDbUser.Text.Trim();
				string dbp = txtDbPassword.Text.Trim();
				if ( svr == "" ) {
					Helper.ShowInfo("SqlServer can't be empty.");
					return;
				}
				if ( dat == "" ) {
					Helper.ShowInfo("Database can't be empty.");
					return;
				}
				if ( !checkWinAuthentication.Checked && dbu == "" ) {
					Helper.ShowInfo("Database user can't be empty.");
					return;
				}

				saveSettings();

				_userAccess.ConnectString = createConnectionString();

StartLogin:

				using ( new WaitMouse() ) {
					_userAccess.LogIn(nam, Helper.GetHashedString(pwd), 0, 2, org, this.ApplicationId);
				}

				if ( _userAccess.UserData.ReturnCode != "OK" ) {
					if ( _userAccess.UserData.ReturnCode == "USER_IS_LOGGED_IN" ) {
						_userAccess.LogOut(_userAccess.UserData, this.ApplicationId);
						goto StartLogin;
					} else {
						Helper.ShowWarning(_userAccess.UserData.ReturnMessage);
						txtPassword.Text = "";
						txtPassword.Focus();
					}
					return;
				}
				this.DialogResult = DialogResult.OK;
				this.Close();
			} catch ( Exception ex ) {
				Helper.ShowException(ex);
			}
		}

		private void loadSettingsFromRegistry()
		{
			string defaultorg = "ABC Inc.";
			string defaultuser = "aa";

			// HKLM \ SOFTWARE\OpenComposite Team\OpenComposite
			string key = @"SOFTWARE\OpenComposite Team\OpenComposite";
			string defaultdb = "repository";

			try {
				RegistryKey regkey = Registry.LocalMachine.OpenSubKey(key);
				if ( regkey == null ) return;

				txtDatabase.Text = regkey.GetValue("SQLDB", defaultdb) as string;
				txtSqlServer.Text = regkey.GetValue("SQLSERVER", "(local)") as string;
				string useWin = regkey.GetValue("USEWINAUTHENTICATION", "0") as string;
				if ( useWin == "0" ) {
					checkWinAuthentication.Checked = false;
					txtDbUser.Text = regkey.GetValue("SQLUSER", "sa") as string;
				} else {
					checkWinAuthentication.Checked = true;
				}
				txtOrg.Text = defaultorg;
				txtUser.Text = defaultuser;
			} catch {
				Debug.WriteLine("Error while loading settings from registry.");
			}
		}

		private void restoreSettings()
		{
			txtOrg.Text = m_settings.GetSetting("OrgName");
			txtUser.Text = m_settings.GetSetting("User");
			txtSqlServer.Text = m_settings.GetSetting("SqlServer");
			txtDatabase.Text = m_settings.GetSetting("Database");
			txtDbUser.Text = m_settings.GetSetting("DBUser");
			txtDbPassword.Text = m_settings.GetSetting("DBPassword");
			try {
				checkWinAuthentication.Checked = Convert.ToBoolean(m_settings.GetSetting("UseWinAuthentication"));
			} catch {
				checkWinAuthentication.Checked = false;
			}
			try {
				numTimeOut.Value = Convert.ToDecimal(m_settings.GetSetting("TimeOut"));
			} catch {
				numTimeOut.Value = 20;
			}
		}

		private void saveSettings()
		{
			m_settings.Autosave = false;
			m_settings.PutSetting("OrgName", txtOrg.Text.Trim());
			m_settings.PutSetting("User", txtUser.Text.Trim());
			m_settings.PutSetting("SqlServer", txtSqlServer.Text.Trim());
			m_settings.PutSetting("Database", txtDatabase.Text.Trim());
			m_settings.PutSetting("DBUser", txtDbUser.Text.Trim());
			m_settings.PutSetting("DBPassword", txtDbPassword.Text.Trim());
			m_settings.PutSetting("UseWinAuthentication", checkWinAuthentication.Checked.ToString());
			m_settings.PutSetting("TimeOut", numTimeOut.Value.ToString());
			m_settings.Autosave = true;
			m_settings.SaveSettings();
		}

		private void setExpandedTabOrder(bool bExpanded)
		{
			btnCreateNewOrg.TabStop = bExpanded;
			txtSqlServer.TabStop = bExpanded;
			txtDatabase.TabStop = bExpanded;
			txtDbUser.TabStop = bExpanded;
			txtDbPassword.TabStop = bExpanded;
			linkTestConn.TabStop = bExpanded;
			checkWinAuthentication.TabStop = bExpanded;
			numTimeOut.TabStop = bExpanded;
		}

		private void setExpandedView(bool bExpanded)
		{
			setExpandedTabOrder(bExpanded);
			if ( bExpanded ) {
				btnDetails.Text = "DB Connection <<";
				this.Height = 500;
			} else {
				btnDetails.Text = "DB Connection >>";
				this.Height = 275;
			}
		}

		private bool testDBConn(bool bShowOKMsg)
		{
			string msg = "";
			using ( WorkingMsgBox wmsg = new WorkingMsgBox() ) {
				wmsg.Show("Testing SQL Connection...");
				using ( SqlConnection conn = new SqlConnection() ) {
					try {
						conn.ConnectionString = createConnectionString();
						conn.Open();
					} catch ( Exception ex ) {
						msg += string.Format("Test connection to sql server '{0}' failed.{1}{1}{2}",
											 txtSqlServer.Text, Environment.NewLine, ex.Message);
					} finally {
						if ( conn.State == ConnectionState.Open ) conn.Close();
					}
				}
			}
			if ( msg.Length > 0 ) {
				MessageBox.Show(msg, "Test connection failed", MessageBoxButtons.OK, MessageBoxIcon.Warning);
				return false;
			} else if ( bShowOKMsg ) {
				MessageBox.Show("Test connection succeeded.", "Test connection", MessageBoxButtons.OK, MessageBoxIcon.Information);
			}
			return true;
		}

		private void doCreateNewOrg()
		{
			if ( !testDBConn(false) ) return;
			_userAccess.ConnectString = createConnectionString();
			_userAccess.LogIn("sa", "H7Cr2ILhAMBjSsBjARzqggm0Fjb2owjgZ4CSXIohdBkQvwarp5QOBVWVE92f//uh7j7yzcIkAWdxwPdTCQeF3g==", 1, 1, "Master", Helper.DesignerApplicationId);

			NewOrgEventArgs e = new NewOrgEventArgs();
			EventHandler<NewOrgEventArgs> tmp = this.ShowCreateNewOrganizationForm;
			if ( tmp != null ) {
				tmp(this, e);
			}
			if ( !string.IsNullOrEmpty(e.NewOrg) ) {
				txtOrg.Text = e.NewOrg;
				txtUser.Text = e.NewUser;
				txtPassword.Text = "";
				txtOrg.Focus();
			}
			_userAccess.LogOut(_userAccess.UserData, Helper.DesignerApplicationId);
		}

		#endregion Methods

		#endregion Private Members
	}

	public class NewOrgEventArgs : EventArgs
	{
		public NewOrgEventArgs()
		{
			NewOrg = "";
			NewUser = "";
		}
		public string NewOrg { get; set; }
		public string NewUser { get; set; }
	}
}